#pragma once
#include "Logger.hpp"
#include "Singleton.h"
#include "const.h"
#include <atomic>
#include <condition_variable>

class Request
{
  public:
    Request()
    {
        _version = "1.1";
    }
    Request(unsigned int method, std::string version, std::string target, std::string body)
        : _version(version), _method(method), _target(target), _body(body)
    {
    }

    std::string version()
    {
        return _version;
    }

    unsigned int method()
    {
        return _method;
    }

    std::string target()
    {
        return _target;
    }

    // std::array<char, 8192> body()
    // {
    //     return _body;
    // }
    std::string body()
    {
        return _body;
    }

  private:
    std::string _version;
    unsigned int _method;
    std::string _target;
    // std::array<char, 8192> _body;     //请求体
    std::string _body;
};

class Response
{
  public:
    Response()
    {
        _version = "1.1";
        _header += "HTTP/" + _version + " " + std::to_string(_status) + " OK" + "\r\n";
    }
    Response(std::string version, unsigned int status) : _version(version), _status(status)
    {
        _version = "1.1";
        _header += "HTTP/" + _version + " " + std::to_string(_status) + " OK" + "\r\n";
    }
    void version(std::string version)
    {
        _version = version;
        // 替换掉原来的版本号
        std::size_t start = _header.find("/") + 1;      // 从第一个"/"后一位处开始
        std::size_t end = _header.find(" ", start + 1); // 到第一个空格处结束
        _header.replace(start, end - start, _version);
    }
    void result(http_status result)
    {
        _status = result;
        // 替换掉原来的状态码
        std::size_t start = _header.find(" ") + 1;  // 从第一个空格处开始
        std::size_t end = _header.find(" ", start); // 到第二个空格处结束
        _header.replace(start, end - start, std::to_string(_status));
    }
    void keep_alive(bool keep_alive)
    {
        _keep_alive = keep_alive;
        std::size_t pos = _header.find("Connection: ");
        if (pos != std::string::npos)
        {
            // 替换掉原来的连接类型
            std::size_t end = _header.find("\r\n", pos);
            _header.replace(pos, end - pos, "Connection: " + std::string(_keep_alive ? "keep-alive" : "close"));
        }
        else
            _header += "Connection: " + std::string(_keep_alive ? "keep-alive" : "close") + "\r\n";
    }
    void content_length(std::string content_length)
    {
        std::size_t pos = _header.find("Content-Length: ");
        if (pos != std::string::npos)
        {
            // 替换掉原来的
            std::size_t end = _header.find("\r\n", pos);
            _header.replace(pos, end - pos, "Content-Length: " + content_length);
        }
        else
            _header += "Content-Length: " + content_length + "\r\n";
    }
    void accept_charset(std::string accept_charset)
    {
        std::size_t pos = _header.find("Accept-Charset: ");
        if (pos != std::string::npos)
        {
            // 替换掉原来的
            std::size_t end = _header.find("\r\n", pos);
            _header.replace(pos, end - pos, "Accept-Charset: " + accept_charset);
        }
        else
            _header += "Accept-Charset: " + accept_charset + "\r\n";
    }
    void content_type(std::string content_type)
    {
        if (content_type.find("image") != std::string::npos)
            _is_img = true;
        std::size_t pos = _header.find("Content-Type: ");
        if (pos != std::string::npos)
        {
            // 替换掉原来的
            std::size_t end = _header.find("\r\n", pos);
            _header.replace(pos, end - pos, "Content-Type: " + content_type);
        }
        else
            _header += "Content-Type: " + content_type + "\r\n";
    }
    void accept_ranges(std::string accept_ranges)
    {
        std::size_t pos = _header.find("Accept-Ranges: ");
        if (pos != std::string::npos)
        {
            // 替换掉原来的
            std::size_t end = _header.find("\r\n", pos);
            _header.replace(pos, end - pos, "Accept-Ranges: " + accept_ranges);
        }
        else
            _header += "Accept-Ranges: " + accept_ranges + "\r\n";
    }
    char *body()
    {
        return _body;
    }
    void set_body(std::string body)
    {
        // memcpy(_body, body.c_str(), body.length());
        // _body[body.length()] = '\0';
        _body_str = body;
    }
    void set_img_body(char *img_body, std::size_t len)
    {
        // TODO:图片太大就会报错（255k都不行？！）
        // memcpy(_body, img_body, len);
        _dump_header_char_ptr = img_body;
        _body_ptr = img_body;
        _img_size = len;
    }
    std::size_t body_length()
    {
        if (strlen(_body) == 8192)
            return 0;
        if (_is_img)
            return _img_size;
        return strlen(_body);
    }
    char *dump_char()
    {
        try
        {
            std::string tmp_header;
            _header.append("\r\n");
            tmp_header = _header;
            if (_is_img) // 如果是图片的话
            {
                memcpy(_dump_header_char_ptr, tmp_header.c_str(), tmp_header.size());
                _total_len = tmp_header.size() + _img_size;
                // LOG_INFO("dump_char:\n{}", _dump_header_char);
                _is_dumped = true;
                return _dump_header_char_ptr;
            }
            else // 不是图片的话
            {
                tmp_header.append(_body);
                memcpy(_dump_header_char, tmp_header.c_str(), tmp_header.size());
                _dump_header_char[tmp_header.size()] = '\0';
                if (strlen(_body) == 8192) // 判断是否为空
                {
                    _body[0] = '\0'; // 直接置空
                }
                _total_len = strlen(_dump_header_char);
                _is_dumped = true;
                return _dump_header_char;
            }

            LOG_INFO("dump_char:\n{}", _dump_header_char);
            // std::cout << _dump_header_char << std::endl;
        }
        catch (const std::exception &e)
        {
            LOG_ERROR("dump_char error: {}", e.what());
        }
    }
    std::string dump()
    {
        _dump_header = _header;
        if (strlen(_body))
            _body[0] = '\0';
        _dump_header += std::string(_body);
        return _dump_header;
    }
    char *getDumped()
    {
        if (_is_dumped)
        {
            if (_is_img)
            {
                return _dump_header_char_ptr;
            }
            else
            {
                return _dump_header_char;
            }
        }
        else
            return nullptr;
    }
    // 进行了dump操作之后才能使用
    int total_len()
    {
        return _total_len;
    }

    std::size_t getHeaderLen()
    {
        if(!_has_got_header)
        {
            _header.append("\r\n");
            LOG_INFO("getHeader:\n{}", _header);
            _has_got_header = true;
        }
        return _header.size();
    }

    std::string& getHeader()
    {
        if(!_has_got_header)
        {
            _header.append("\r\n");
            LOG_INFO("getHeader:\n{}", _header);
            _has_got_header = true;
        }
        return _header;
    }

    std::size_t getBodyLen()
    {
        if (_is_img)
            return _img_size;
        else
            return _body_str.size();
    }

    char * get_img_body()
    {
        return _body_ptr;
    }

    std::string& get_body_str()
    {
        return _body_str;
    }

    bool _is_img = false;

  private:
    std::string _version;
    char _body[8192];                       // 响应体
    char* _body_ptr;                         //指针式响应体
    std::string _body_str;                  //响应体
    std::string _header;                    // 响应头
    unsigned int _status = http_status::ok; // 状态m默认是ok
    bool _keep_alive;                       // 是否保持连接
    char _dump_header_char[9216];           // 响应
    char *_dump_header_char_ptr;            // 指针形式的响应，用于处理图片响应
    bool _is_dumped;                        // 是否已经dump过
    std::string _dump_header;               // 响应
    std::size_t _total_len;
    std::size_t _img_size = 0;
    bool _has_got_header=false;
};

class HttpConnection : public std::enable_shared_from_this<HttpConnection>
{
  public:
    HttpConnection(boost::asio::io_context &ioc); // 构造函数，用于初始化socket
    void Start();
    tcp::socket &GetSocket();
    friend class LogicSystem;

  private:
    void PreParseGetParam(); // 对get请求的url进行预处理
    void ReadReq();          // 读取请求
    void HandleReq();        // 处理请求
    void CheckDeadline();    // 检测超时函数
    void WriteResponse();    // 发送响应
    void HandleNotFound();   // 处理未找到路径
    void HandleSuccess();    // 处理成功响应
    void Handle_Write_Header();     // 发送响应头
    void Handle_Write_Body();       //发送响应体
    tcp::socket _socket;     // 套接字，用于发送来的数据
    // boost::beast::flat_buffer _buffer{8192};      // 缓冲区，用于暂存数据
    char _buffer[8192]; // 缓冲区
    // http::request<http::dynamic_body> _request;   // 请求
    // http::response<http::dynamic_body> _response; // 响应
    Request _request;
    Response _response;
    // The timer for putting a deadline on connection processing.
    boost::asio::steady_timer _deadline{_socket.get_executor(), std::chrono::seconds(60)};
    std::atomic<bool> _is_write_complete = false; // 数据是否已经全部传输完毕，若没有则继续读取
    std::atomic<std::size_t> _bytes_written = 0;  // 已经写入的长度
    std::string _get_url;                         // 处理过后的url
    std::unordered_map<std::string, std::string> _get_params; // get请求携带的参数
    std::atomic<std::size_t> _read_len=0;                       // 已读取的长度，用于判断是否读取完毕
    std::atomic<std::size_t> _head_len=0; // 请求头长度，用于配合_read_len判断是否读取完毕
    std::atomic<int> _last_edit;        // 缓冲区中上一次编辑的位置
    std::condition_variable _cv;        // 缓冲区的条件变量
    std::mutex _mtx;
    bool _is_data_ready=false; // 图片数据是否已经准备好了
    std::size_t _written_header_len=0;
    std::size_t _written_body_len=0;
    std::size_t _bytes_read=0;      //当前图片读取长度
    bool _body_sent;        //当前数据是否发送完毕
    // std::vector<char> _body_buffer{'\0'};         //响应体缓冲
};